package top.rainbowecho.gateway.security.authentication.mail;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import top.rainbowecho.common.util.CommonUtil;
import top.rainbowecho.common.util.ExceptionMessageContent;

import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
import static org.apache.commons.lang3.StringUtils.isEmpty;

/**
 * @author rainbow
 * @since 2019/12/15 10:27
 */
public class MailAuthenticationProvider implements AuthenticationProvider {
    private UserDetailsService userDetailsService;

    private StringRedisTemplate redisTemplate;

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MailAuthenticationToken mailAuthenticationToken = (MailAuthenticationToken) authentication;

        String mail = (String) mailAuthenticationToken.getPrincipal();
        long timestamp = mailAuthenticationToken.getTimestamp();
        String code = mailAuthenticationToken.getCode();

        // 取出redis对应的邮箱验证码
        String codeKey = CommonUtil.validateCodeKey(mail, timestamp);
        String mailCode = redisTemplate.opsForValue().get(codeKey);

        boolean isExpire = isEmpty(mailCode);
        if (isExpire) {
            throw new MailAuthenticationException(ExceptionMessageContent.CODE_INVALIDATE);
        }

        boolean isCorrect = equalsIgnoreCase(code, mailCode);
        if (!isCorrect) {
            throw new MailAuthenticationException(ExceptionMessageContent.WRONG_CODE);
        }

        // 查本地数据库验证邮件
        UserDetails userDetails = userDetailsService.loadUserByUsername(mail);
        if (userDetails == null) {
            throw new InternalAuthenticationServiceException(ExceptionMessageContent.INVALID_MAIL);
        }

        // 重新构造认证成功的token
        MailAuthenticationToken authenticationResult = new MailAuthenticationToken(userDetails, userDetails.getAuthorities());
        authenticationResult.setDetails(mailAuthenticationToken.getDetails());

        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MailAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
